#include "stdafx.h"
#include "view.h"
#include "proc.h"

namespace xm
{
	STDMETHODIMP image_view_t::GetPaga( UINT64 offset, UINT32 * paga )
	{
		return section->get_page_paga( offset, paga );
	}
	STDMETHODIMP image_view_t::GetRamBlock( UINT64 offset, rmb_t ** pprmb )
	{
		rmb_t * rmbp = section->get_page_rmb( offset );
		if( !rmbp ) return E_FAIL;
		*pprmb = rmbp;
		return S_OK;
	}
	image_view_t::image_view_t( vmarea_t & ar, process_t* proc) 
			: inproc(*proc)
			, stand( ar )
			, ldopt(0)
	{
	}
	image_view_t::~image_view_t()
	{
		close();
	}
	imagex_t * image_view_t::image_object()
	{
		return section->ko->proto<imagex_t>();
	}
	uint64_t image_view_t::get_size()
	{
		return section->get_size();
	}
	void image_view_t::close()
	{
		if( !section ) return ;
		section->remove_user(this);
		uint64_t ssize = section->get_size();
		for( uint64_t off = 0; off < ssize; off += VM_PAGE_SIZE )
		{
			uint64_t invalid_vma = stand.base + off;
			inproc.vmm_unmap( invalid_vma );
		}
		section.dispose();
		mi.clear();
	}

	long image_view_t::on_section_invalid( section_t * secp, uint64_t offset )
	{
		uint64_t invalid_vma = stand.base + offset;
		return inproc.vmm_invalid( invalid_vma );
	}
	long image_view_t::open( section_t * sec, int16_t ldcnt )
	{
		if( section ) return E_UNEXPECTED;
		if( !sec || !sec->ko )
			return E_INVALIDARG;
		if( sec->ko->Class() != KoImage )
			return E_INVALIDARG;
		section = sec;
		mi.loadcount = ldcnt;
		mi.timestamp = 0;
		mi.tls_index = 0;
		section->insert_user( this );
		return S_OK;
	}


	file_view_t::file_view_t( vmarea_t & ar, process_t* proc) 
		: inproc(*proc)
		, stand(ar)
		, begin(0)
		, length(0)
	{
	}
	file_view_t::~file_view_t()
	{
		close();
	}
	//////////////////////////////////////////////////////////////////////////
	STDMETHODIMP file_view_t::GetPaga( UINT64 offset, UINT32 * paga )
	{
		if( length <= offset ) return E_FAIL;
		return section->get_page_paga( begin + offset, paga );
	}
	STDMETHODIMP file_view_t::GetRamBlock( UINT64 offset, rmb_t ** pprmb )
	{
		if( length <= offset ) return E_FAIL;
		rmb_t * rmbp = section->get_page_rmb( begin + offset );
		if( !rmbp ) return E_FAIL;
		*pprmb = rmbp;
		return S_OK;
	}
	long file_view_t::open( section_t * sec, uint64_t offset, uint64_t size )
	{
		if( !sec ) return E_FAIL;

		uint64_t sec_len = sec->get_size();
		if( offset >= sec_len ) 
			return E_FAIL;

		if( size == (uint64_t)-1 )
		{
			size = sec_len - offset;
		}
		else
		{
			if( offset + size > sec_len )
				return E_FAIL;
		}
		begin = offset;
		length = size;
		section = sec;
		section->insert_user( this );
		return S_OK;
	}
	void file_view_t::close()
	{
		section->remove_user(this);
		uint64_t endp = begin + length;
		for( uint64_t off = begin; off < endp; off += VM_PAGE_SIZE )
		{
			rmb_t* pref = section->get_ram_block( off, false );
			if( !pref ) continue;
			uint64_t invalid_vma = stand.base + off - begin;
			inproc.vmm_unmap( invalid_vma );
		}
	}
	long file_view_t::on_section_invalid( section_t * secp, uint64_t off )
	{
		if( off < begin ) return 0;
		if( begin + length <= off ) return 0;
		uint64_t invalid_vma = stand.base + off - begin;
		return inproc.vmm_invalid( invalid_vma );
	}

};
